/**
 * Copyright 2011 FeedDreamwork SIG
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package org.feeddreamwork.feed;

import java.text.*;

import org.feeddreamwork.*;
import org.w3c.dom.*;

public class Atom10FeedParser extends FeedParser {
	@Override
	public boolean isThisType(Document source) {
		Element root = source.getDocumentElement();
		if (root.getNodeName().equals("feed")
				&& FeedConstant.ATOM_10_NAMESPACE.equals(root
						.getAttribute("xmlns")))
			return true;
		else
			return false;
	}

	@Override
	public Feed parse(Document source, String baseURL)
			throws FeedParsingException {
		Utils.throwIfNull(source);
		Element root = source.getDocumentElement();

		if (Utils.isNullOrEmpty(baseURL)) {
			String selfURL = findAtomLink(root, "self");
			if (!Utils.isNullOrEmpty(selfURL))
				baseURL = resolveURL(root, selfURL, null);
		}

		Feed feed = parseFeedMetadata(root, baseURL);
		NodeList childNodes = root.getChildNodes();
		for (int i = 0; i < childNodes.getLength(); i++)
			if (childNodes.item(i).getNodeName().equals("entry")) {
				Element entry = (Element) childNodes.item(i);
				feed.getEntries().add(parseEntry(feed, entry, baseURL));
			}
		return feed;
	}

	@Override
	protected String resolveURL(Node node, String url, String baseURL)
			throws FeedParsingException {
		if (Utils.isAbsoluteURL(url))
			return url;
		if (node != null && node instanceof Element) {
			String xmlBase = ((Element) node).getAttribute("xml:base");
			if (!Utils.isNullOrEmpty(xmlBase)) {
				if (!Utils.isAbsoluteURL(xmlBase))
					xmlBase = resolveURL(node.getParentNode(), xmlBase, baseURL);
				return super.resolveURL(node, url, xmlBase);
			}
			return resolveURL(node.getParentNode(), url, baseURL);
		}
		return super.resolveURL(node, url, baseURL);
	}

	@Override
	protected Feed parseFeedMetadata(Element root, String baseURL)
			throws FeedParsingException {
		String title = XMLUtils.findSimpleElement(root, "title");
		String link = findAtomLink(root, "alternate");
		if (Utils.isNullOrEmpty(title) || Utils.isNullOrEmpty(link))
			throw new FeedParsingException();
		link = resolveURL(root, link, baseURL);
		Feed feed = new Feed(title, link);

		feed.setDescription(XMLUtils.findSimpleElement(root, "subtitle"));
		String image = XMLUtils.findSimpleElement(root, "icon");
		if (Utils.isNullOrEmpty(image))
			image = XMLUtils.findSimpleElement(root, "logo");
		feed.setImage(image);
		feed.setLanguage(root.getAttribute("xml:lang"));
		return feed;
	}

	@Override
	protected Entry parseEntry(Feed feed, Element entry, String baseURL)
			throws FeedParsingException {
		String title = XMLUtils.findSimpleElement(entry, "title");
		String link = findAtomLink(entry, "alternate");
		String content = XMLUtils.findSimpleElement(entry, "content");
		String author = parseAuthor(entry);
		String updatedTime = XMLUtils.findSimpleElement(entry, "published");
		if (updatedTime == null)
			updatedTime = XMLUtils.findSimpleElement(entry, "updated");
		
		if (Utils.isNullOrEmpty(title) || Utils.isNullOrEmpty(link)
				|| Utils.isNullOrEmpty(updatedTime))
			throw new FeedParsingException();
		link = resolveURL(entry, link, baseURL);
		if (Utils.isNullOrEmpty(content))
			content = XMLUtils.findSimpleElement(entry, "summary");
		if (Utils.isNullOrEmpty(author))
			author = feed.getTitle();
		try {
			return new Entry(title, link, content, author,
					DateUtils.parseISO8601Date(updatedTime));
		} catch (ParseException e) {
			throw new FeedParsingException();
		}
	}

	private String findAtomLink(Element node, String rel) {
		Utils.throwIfNull(node);
		Utils.throwIfNullOrEmpty(rel);

		NodeList childNodes = node.getChildNodes();
		for (int i = 0; i < childNodes.getLength(); i++)
			if (childNodes.item(i).getNodeName().equals("link")) {
				Element link = (Element) childNodes.item(i);
				String findRel = link.getAttribute("rel");
				if (Utils.isNullOrEmpty(findRel) && rel.equals("alternate")
						|| !Utils.isNullOrEmpty(findRel) && findRel.equals(rel))
					return link.getAttribute("href");
			}
		return null;
	}

	private String parseAuthor(Element node) {
		NodeList childNodes = node.getChildNodes();
		for (int i = 0; i < childNodes.getLength(); i++)
			if (childNodes.item(i).getNodeName().equals("author")) {
				Element author = (Element) childNodes.item(i);
				return XMLUtils.findSimpleElement(author, "name");
			}
		if (node != null && node instanceof Element)
			return parseAuthor((Element) node.getParentNode());
		return null;
	}
}
